/**
 * 
 */
package com.dalonedrau.jogl.opengl.sprite;

import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;

/**
 * @author Donald
 */
public final class SpriteImageObjectFactory {
	/**
	 * the one and only instance of the <code>SpriteImageObjectFactory</code>
	 * class.
	 */
	private static SpriteImageObjectFactory	instance;
	/**
	 * Gives access to the singleton instance of
	 * {@link SpriteImageObjectFactory}.
	 * @return {@link SpriteImageObjectFactory}
	 */
	public static SpriteImageObjectFactory getInstance() {
		if (SpriteImageObjectFactory.instance == null) {
			SpriteImageObjectFactory.instance = new SpriteImageObjectFactory();
		}
		return SpriteImageObjectFactory.instance;
	}
	/** the list of images. */
	private SpriteImageObject[]	images	= new SpriteImageObject[10];
	/** the list of image names used. */
	private String[]			names	= new String[10];
	/** the next available image id. */
	private int					nextId	= 0;
	/**
	 * Attempts to add an image to the {@link SpriteImageObjectFactory}.
	 * @param imageName the image's name
	 * @param image the {@link SpriteImageObject}
	 * @throws Exception if the image could not be loaded
	 */
	public void addImage(final String imageName,
			final SpriteImageObject image) throws Exception {
		if (imageName == null) {
			PooledStringBuilder sb = StringBuilderPool.getInstance()
					.getStringBuilder();
			sb.append("ERROR! SpriteImageObjectFactory.addImage() - ");
			sb.append("null value sent in parameters");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		if (image == null) {
			PooledStringBuilder sb = StringBuilderPool.getInstance()
					.getStringBuilder();
			sb.append("ERROR! SpriteImageObjectFactory.addImage() - ");
			sb.append("null value sent in parameters");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		if (hasImage(imageName)) {
			PooledStringBuilder sb = StringBuilderPool.getInstance()
					.getStringBuilder();
			sb.append("ERROR! SpriteImageObjectFactory.addImage() - ");
			sb.append("image '");
			sb.append(imageName);
			sb.append("' already loaded");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		if (image.getRefId()< images.length
				&& images[image.getRefId()] != null) {
			PooledStringBuilder sb = StringBuilderPool.getInstance()
					.getStringBuilder();
			sb.append("ERROR! SpriteImageObjectFactory.addImage() - ");
			sb.append("image '");
			sb.append(imageName);
			sb.append("' assigned invalid refId.  RefId already in use.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		if (image.getRefId() >= images.length) {
			// extend the names array
			String[] tempStr = new String[image.getRefId() + 1];
			System.arraycopy(names, 0, tempStr, 0, names.length);
			names = tempStr;
			// extend the images array
			SpriteImageObject[] tempImg =
					new SpriteImageObject[image.getRefId() + 1];
			System.arraycopy(images, 0, tempImg, 0, images.length);
			images = tempImg;
		}
		names[image.getRefId()] = imageName;
		images[image.getRefId()] = image;
	}
	/**
	 * Gets a {@link SpriteImageObject} by its reference id.
	 * @param id the reference id
	 * @return {@link SpriteImageObject}
	 * @throws Exception if the image does not exist
	 */
	public SpriteImageObject getImageById(final int id) throws Exception {
		SpriteImageObject image = null;
		if (id >= 0
				&& id < images.length) {
			image = images[id];
		}
		if (image == null) {
			PooledStringBuilder sb = StringBuilderPool.getInstance()
					.getStringBuilder();
			sb.append("ERROR! SpriteImageObjectFactory.getImageById() - ");
			sb.append("invalid refId. image with refId");
			sb.append(id);
			sb.append(" was never loaded.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return image;
	}
	/**
	 * Gets a {@link SpriteImageObject} by its name.
	 * @param imageName the image's name
	 * @return {@link SpriteImageObject}
	 * @throws Exception if the image does not exist
	 */
	public SpriteImageObject getImageByName(final String imageName)
			throws Exception {
		SpriteImageObject image = null;
		int id = -1;
		for (int i = 0; i < names.length; i++) {
			if (names[i] != null
					&& names[i].equalsIgnoreCase(imageName)) {
				id = i;
				break;
			}
		}
		if (id >= 0
				&& id < images.length) {
			image = images[id];
		}
		if (image == null) {
			PooledStringBuilder sb = StringBuilderPool.getInstance()
					.getStringBuilder();
			sb.append("ERROR! SpriteImageObjectFactory.getImageByName() - ");
			sb.append("invalid refId. image '");
			sb.append(imageName);
			sb.append("' was never loaded.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return image;
	}
	/**
	 * Gets the reference id for a specific image.
	 * @param imageName the image's name
	 * @return int
	 * @throws Exception if the image was not loaded
	 */
	public int getImageRefId(final String imageName) throws Exception {
		int id = -1;
		for (int i = 0; i < names.length; i++) {
			if (names[i] != null
					&& names[i].equals(imageName)) {
				id = i;
				break;
			}
		}
		if (id == -1) {
			PooledStringBuilder sb = StringBuilderPool.getInstance()
					.getStringBuilder();
			sb.append("ERROR! SpriteImageObjectFactory.getImageRefId() - ");
			sb.append("invalid name: '");
			sb.append(imageName);
			sb.append("'");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return id;
	}
	/**
	 * Gets the next available image id.
	 * @return int
	 */
	public int getNextId() {
		return nextId++;
	}
	/**
	 * Determines if the {@link SpriteImageObjectFactory} has an image by a
	 * specific name.
	 * @param imageName the image's name
	 * @return true if an image by that name has been stored already; false
	 *         otherwise
	 */
	public boolean hasImage(final String imageName) {
		boolean has = false;
		for (int i = 0; i < names.length; i++) {
			if (imageName != null
					&& names[i] != null
					&& imageName.equals(names[i])) {
				has = true;
				break;
			}
		}
		return has;
	}
}
